package nio.demo;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
 * @Desc:   NIO AsynchronousFileChannel 案例
 * @author: cww
 * @DateTime: 2020-02-05 9:48
 */

public class AsynchronousFileChannelExample {

    public static void main(String[] args) throws Exception {
//        readDataByFuture();
        readDataByCompletionHandler();
//        writeDataByFuture();
//        writeDataByCompletionHandler();
    }

    /**
     * 通过Future阅读数据
     * 使用 AsynchronousFileChannel.read(ByteBuffer dst, long position); 读取数据
     */
    public static void readDataByFuture() throws Exception {
        // 开启一个异步 FileChannel 通道
        Path path = Paths.get("C:\\Code\\spring-root\\src\\maindemo\\resources\\file\\nio\\nio-data.txt");
        // 第二个参数是一个或多个打开选项，告诉 AsynchronousFileChannel 在底层文件上执行哪些操作
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);

        ByteBuffer buf = ByteBuffer.allocate(1024);
        buf.clear();
        // 通过Future阅读数据,数据将被读入 buf ，第二个参数是起始位置
        // read() 方法会立即返回，即使读操作还没有完成，
        // 通过调用 read() 方法返回的 Future 实例的 isDone() 方法，可以用来检查读取操作是否完成
        Future<Integer> operation = fileChannel.read(buf, 0);
        while (!operation.isDone()) {
            System.out.println("waiting");
        }
        buf.flip();
        byte[] data = new byte[buf.limit()];
        buf.get(data);
        System.out.println(new String(data));
        buf.clear();
    }

    /**
     * 通过一个CompletionHandler读取数据
     * AsynchronousFileChannel.read(ByteBuffer dst, long position, A attachment,
     *                                      CompletionHandler<Integer,? super A> handler);
     * @throws Exception
     */
    public static void readDataByCompletionHandler() throws Exception {
        // 开启一个异步 FileChannel 通道
        Path path = Paths.get("C:\\Code\\spring-root\\src\\maindemo\\resources\\file\\nio\\nio-data.txt");
        // 第二个参数是一个或多个打开选项，告诉 AsynchronousFileChannel 在底层文件上执行哪些操作
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
        ByteBuffer buf = ByteBuffer.allocate(1024);
        ByteBuffer buf1 = ByteBuffer.allocate(1024);

        fileChannel.read(buf, 0, buf, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                System.out.println("result1 = " + result);
                attachment.flip();
                byte[] data = new byte[attachment.limit()];
                attachment.get(data);
                System.out.println("resultData:" + new String(data));
                System.out.println("done");
                attachment.clear();
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                System.out.println("failed");
            }
        });

        int cTime = 0;
        while(cTime < 5) {
            try {
                Thread.sleep(500);
                ++cTime;
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /**
     * 通过Future写数据
     * @throws Exception
     */
    public static void writeDataByFuture() throws Exception {
        // 开启一个异步 FileChannel 通道
        Path path = Paths.get("C:\\Code\\spring-root\\src\\maindemo\\resources\\file\\nio\\nio-data.txt");
        long position = 0;
        if (! Files.exists(path)) {
            Files.createDirectory(path);
        } else {
            // 如果文件已经存在了，那么要知道里面有多少字节内容，后面进行写数据时，进行追加写
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            position = fileChannel.size();
            fileChannel.close();
        }
        // 首先，AsynchronousFileChannel以写模式打开
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
        ByteBuffer buf = ByteBuffer.allocate(1024);

        buf.put("test data".getBytes());
        buf.flip();
        // 以如下方式写入，若文件中已经有内容，那么将覆盖现有内容，如果要追加，
        // 那么先要检查文件内的字节长度，让 position 大于字节长度
        Future<Integer> operation = fileChannel.write(buf, position);
        buf.clear();
        while (!operation.isDone());
        System.out.println("Write done");
    }

    /**
     * 通过一个CompletionHandler写入数据
     */
    public static void writeDataByCompletionHandler() throws Exception {
        Path path = Paths.get("C:\\Code\\spring-root\\src\\maindemo\\resources\\file\\nio\\writeDataCom.txt");
        long position = 0;
        if(!Files.exists(path)){
            Files.createFile(path);
        } else {
            // 如果文件已经存在了，那么要知道里面有多少字节内容，后面进行写数据时，进行追加写
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            position = fileChannel.size();
            fileChannel.close();
        }
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(("\ntest data").getBytes());
        buffer.flip();
        fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                System.out.println("bytes written: " + result);
                attachment.flip();
                byte[] data = new byte[attachment.limit()];
                attachment.get(data);
                System.out.println(new String(data));
                attachment.clear();
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                System.out.println("Write failed ");
                exc.printStackTrace();
            }
        });
    }
}


















